package com.liao.tensquare.admin.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.google.gson.Gson;
import com.liao.tensquare.constants.UserConstant;
import com.liao.tensquare.constants.TokenConstants;
import com.liao.tensquare.admin.dao.TbUserDao;
import com.liao.tensquare.entity.JWTInfo;
import com.liao.tensquare.entity.Result;
import com.liao.tensquare.entity.StatusCode;
import com.liao.tensquare.exception.ParamsException;
import com.liao.tensquare.exception.RecordException;
import com.liao.tensquare.exception.UserInvalidException;
import com.liao.tensquare.exception.UserRegisteredException;
import com.liao.tensquare.admin.pojo.TbPermission;
import com.liao.tensquare.admin.pojo.TbRole;
import com.liao.tensquare.admin.pojo.TbUser;
import com.liao.tensquare.admin.service.PermissionService;
import com.liao.tensquare.admin.service.TbUserService;
import com.liao.tensquare.utils.IdWorker;
import com.liao.tensquare.utils.JwtTokenUtil;
import com.liao.tensquare.utils.RedisConstant;
import com.liao.tensquare.utils.StringHelper;
import com.liao.tensquare.admin.vo.Permission;
import com.liao.tensquare.admin.vo.Role;
import com.liao.tensquare.admin.vo.UserInfoResponse;
import com.liao.tensquare.admin.vo.UserVO;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * 用户(TbUser)表服务实现类
 *
 * @author long
 * @since 2021-07-16 17:00:08
 */
@Service("tbUserService")
public class TbUserServiceImpl implements TbUserService {
    @Resource
    private TbUserDao tbUserDao;
    @Resource
    private PermissionService permissionService;
    @Autowired
    private IdWorker idWorker;
    @Autowired
    private StringRedisTemplate redisTemplate;
    @Autowired
    private BCryptPasswordEncoder passwordEncoder;

    private final Gson gson = new Gson();

    @Override
    public UserInfoResponse findCurrentUserById(String userId) {
        UserInfoResponse userInfo = null;
        TbUser tbUser = tbUserDao.selectById(userId);
        if (null != tbUser) {
            userInfo = getUserInfoResponse(tbUser);
            writeUserInfo(userInfo);
        }
        return userInfo;
    }

    @Override
    public UserInfoResponse findUserById(String userId) {
        UserInfoResponse userInfo = null;
        TbUser tbUser = tbUserDao.selectById(userId);
        if (null != tbUser) {
            userInfo = getUserInfoResponse(tbUser);
        }
        return userInfo;
    }

    @Override
    public void register(TbUser user) throws UserRegisteredException {
        Map<String, Object> map = new HashMap<>();
        map.put("account", user.getAccount());
        List<TbUser> userList = tbUserDao.selectByMap(map);
        if (userList.size() != 0) {
            throw new UserRegisteredException();
        }
        user.setId(String.valueOf(idWorker.nextId()));
        Date date = new Date();
        BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
        String password = encoder.encode(user.getPassword());
        user.setPassword(password);
        user.setOnline(0L);
        user.setRegdate(date);
        user.setUpdatedate(date);
        user.setLastdate(date);
        tbUserDao.insert(user);
    }

    @Override
    public Map<String, Object> login(Map<String, String> map) throws UserInvalidException {
        String username = map.get("username");
        String password = map.get("password");
        TbUser tbUser = tbUserDao.selectByAccess(username);
        if (tbUser == null) {
            throw new UserInvalidException("用户名不存在或已注销!");
        }
        BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
        if (encoder.matches(password, tbUser.getPassword())) {
            return getJWTInfo(tbUser);
        }
        throw new UserInvalidException("密码错误!");
    }

    @Override
    public void logout(String tokenId) {
        redisTemplate.delete(RedisConstant.REDIS_USER_TOKEN_KEY + ":" + tokenId);
        redisTemplate.delete(RedisConstant.REDIS_USER_INFO_KEY + ":" + tokenId);
    }

    @Override
    public UserVO findByPage(int offset, int limit, Map<String, Object> columnsData, Date beginCreateDate, Date endCreateDate) {
        UserVO userVO = new UserVO();
        Page<TbUser> page = new Page<>(offset, limit);
        QueryWrapper<TbUser> queryWrapper = new QueryWrapper<>();
        for (String key : columnsData.keySet()) {
            queryWrapper.like(key, columnsData.get(key));
        }
        queryWrapper.between(beginCreateDate != null && endCreateDate != null, "regdate", beginCreateDate, endCreateDate);
        tbUserDao.selectPage(page, queryWrapper);
        List<TbUser> records = page.getRecords();
        List<UserInfoResponse> users = new ArrayList<>();
        for (TbUser tbUser : records) {
            UserInfoResponse userInfoResponse = new UserInfoResponse();
            BeanUtils.copyProperties(tbUser, userInfoResponse);
            users.add(userInfoResponse);
        }
        userVO.setUserInfo(users);
        userVO.setTotal(page.getTotal());
        userVO.setCurrent(page.getCurrent());
        userVO.setSize(page.getSize());
        return userVO;
    }

    @Override
    public List<UserInfoResponse> findList(String ids) {
        String[] split = ids.split(",");
        List<TbUser> tbUsers = tbUserDao.selectBatchIds(Arrays.asList(split));
        List<UserInfoResponse> users = new ArrayList<>();
        BeanUtils.copyProperties(tbUsers, users);
        return users;
    }

    /**
     * 更新用户的信息
     */
    @Override
    public void updateUser(TbUser tbUser) {
        tbUser.setUpdatedate(new Date());
        //更新实体类里面不为null的列
        tbUserDao.updateById(tbUser);
    }

    @Override
    public Result delUser(String ids) {
        if (StringHelper.isEmpty(ids)) {
            throw new ParamsException("id不能为空");
        }
        List<UserInfoResponse> users = findList(ids);
        if (null == users) {
            throw new RecordException("未找到记录");
        }
        int delCount = tbUserDao.delUsers(ids);
//        String[] split = ids.split(",");
//        int i = split.length - delCount;
        return new Result(true, "删除成功", StatusCode.OK);
    }

    @Override
    public void restPassword(String id) {
//        TbUser user = tbUserDao.selectById(id);
        //加密同一个字符串会返回不同的值，但是matches()方法返回的还是true
        String encode = passwordEncoder.encode(UserConstant.USER_PASSWORD);
        UpdateWrapper<TbUser> updateWrapper = new UpdateWrapper<>();
        updateWrapper.eq("id",id);
        updateWrapper.set("password",encode);
        tbUserDao.update(null,updateWrapper);
    }

    @Override
    public Result updatePassword(String userId, String oldPwd, String newPwd) {
        TbUser tbUser = tbUserDao.selectById(userId);
        if (passwordEncoder.matches(oldPwd,tbUser.getPassword())) {
            UpdateWrapper<TbUser> updateWrapper = new UpdateWrapper<>();
            updateWrapper.set("password",passwordEncoder.encode(newPwd));
            updateWrapper.eq("id",userId);
            tbUserDao.update(null,updateWrapper);
            return new Result(true,"更新成功",StatusCode.OK);
        }else {
            return new Result(false,"密码错误",StatusCode.PASSWORD_ERROR);
        }
    }

    private Map<String, Object> getJWTInfo(TbUser tbUser) {
        JWTInfo jwtInfo = new JWTInfo();
        BeanUtils.copyProperties(tbUser, jwtInfo);
        String token = JwtTokenUtil.generateToken(jwtInfo, TokenConstants.SECRET_KEY);
        updateUserLoginInfo(tbUser);
        UserInfoResponse responseUser = getUserInfoResponse(tbUser);
        HashMap<String, Object> result = new HashMap<>();
        result.put("accessToken", token);
        result.put("tokenId", jwtInfo.getId());
        writeOnlineLog(jwtInfo, responseUser);
        return result;
    }

    /**
     * 更新用户登录信息
     */
    private void updateUserLoginInfo(TbUser tbUser) {
        Date date = new Date();
        tbUser.setLastdate(date);
        tbUserDao.updateById(tbUser);
    }

    /**
     * 封装返回的数据
     *
     * @param tbUser
     * @return
     */
    private UserInfoResponse getUserInfoResponse(TbUser tbUser) {
        List<TbPermission> tbPermissions = permissionService.getPermissionsByUserId(tbUser.getId());
        ArrayList<TbRole> tbRoles = tbUserDao.findRoleByUserId(tbUser.getId());
        List<Role> roles = new ArrayList<>();
        List<Permission> permissions = new ArrayList<>();
        UserInfoResponse responseUser = new UserInfoResponse();
        for (TbPermission tbPermission : tbPermissions) {
            Permission permission = new Permission();
            BeanUtils.copyProperties(tbPermission, permission);
            permissions.add(permission);
        }
        for (TbRole tbRole : tbRoles) {
            Role role = new Role();
            BeanUtils.copyProperties(tbRole, role);
            roles.add(role);
        }
        BeanUtils.copyProperties(tbUser, responseUser);
        responseUser.setPermissions(permissions);
        responseUser.setRoles(roles);
        return responseUser;
    }

    /**
     * 把Token信息和用户信息存入Redis
     *
     * @param jwtInfo Token的信息
     */
    public void writeOnlineLog(JWTInfo jwtInfo, UserInfoResponse userInfo) {
        redisTemplate.opsForValue().set(RedisConstant.REDIS_USER_TOKEN_KEY + ":" + jwtInfo.getId(), gson.toJson(jwtInfo, JWTInfo.class), RedisConstant.REDIS_USER_TOKEN_EXPIRED_TIME, TimeUnit.SECONDS);
        writeUserInfo(userInfo);
    }


    public void writeUserInfo(UserInfoResponse userInfo) {
        redisTemplate.opsForValue().set(RedisConstant.REDIS_USER_INFO_KEY + ":" + userInfo.getId(), gson.toJson(userInfo, UserInfoResponse.class), RedisConstant.REDIS_USER_TOKEN_EXPIRED_TIME, TimeUnit.SECONDS);
    }

//    @Override
//    public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {
//        if (null == s | "".equals(s)){
//            /*
//                对被AbstractUserDetailsAuthenticationProvider类转成BadCredentialsException();
//                所以直接替换掉
//            */
//            throw new UsernameNotFoundException("用户名不能为空");
//        }
//        TbUser user = tbUserDao.selectByAccess(s);
//        System.out.println("user====="+user.toString());
//        JWTInfo jwtInfo = new JWTInfo();
//        BeanUtils.copyProperties(user, jwtInfo);
//        String token = JwtTokenUtil.generateToken(jwtInfo, secretKey);
//
//        writeOnlineLog(jwtInfo);
//        ArrayList<GrantedAuthority> list = new ArrayList<>();
//        List<TbRole> tbRoles = roleDao.selectRoleByUserId(user.getId());
//        for (TbRole tbRole : tbRoles) {
//            list.add(new SimpleGrantedAuthority(tbRole.getName()));
//        }
//        return new User(s, user.getPassword(), list);
//    }


}
